<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
  </style>
</head>

<body>
  <canvas id="canvas"></canvas>
  <canvas id="canvas2"></canvas>
  <canvas id="canvas3" width=300 height=400></canvas>
</body>

</html>
<script>
  class Progress {
    constructor(id, w, r, percent) {
      this.canvas = document.getElementById(id);
      this.ctx = this.canvas.getContext('2d');
      this.canvas.width = w * 2;
      this.canvas.height = w * 2;
      this.canvas.style.width = w + 'px';
      this.canvas.style.height = w + 'px';
      this.ctx.translate(0.5, 0.5)
      this.ctx.translate(-0.5, -0.5)

      this.w = w;
      this.r = r;
      this.percent = percent;
      // this.render()
      this.i = 0;

      this.animate()
    }
    animate(){
      this.i++;
      this.render(this.i);
      if(this.i < this.percent){
        requestAnimationFrame(this.animate.bind(this))
      }
    }
    render(i) {
      this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)
      this.ctx.beginPath();
      this.ctx.lineWidth = this.r;
      let grad = this.ctx.createLinearGradient(0,0,this.w*2,0);
      grad.addColorStop(0,'rgba(255,0,0,1)')
      grad.addColorStop(1,'rgba(255,0,0,0.2)')
      this.ctx.strokeStyle = grad;
      // this.ctx.arc(this.w,this.w,this.w-this.r/2,-Math.PI / 2,this.percent/100*Math.PI*2-Math.PI/2)
      this.ctx.arc(this.w,this.w,this.w-this.r/2,-Math.PI / 2,i/100*Math.PI*2-Math.PI/2)
      this.ctx.stroke()
      this.ctx.closePath();

      // 开始位置的小圆
      this.ctx.beginPath()
      this.ctx.strokeStyle = '#000';
      this.ctx.lineWidth = 1;
      this.ctx.arc(this.w,this.r/2,this.r/2,0,Math.PI*2)
      this.ctx.stroke();
      this.ctx.fillStyle = '#fff'
      this.ctx.fill()
      this.ctx.closePath()

      // 结束位置的小圆
      this.ctx.beginPath()
      this.ctx.lineWidth = 1;
      let rad = i/100*Math.PI*2-Math.PI/2;
      // let rad = this.percent/100*Math.PI*2-Math.PI/2;
      let x = (this.w-this.r/2)*Math.cos(rad) + this.w;
      let y = (this.w-this.r/2)*Math.sin(rad) + this.w;
      this.ctx.arc(x,y,this.r/2,0,Math.PI*2)
      this.ctx.stroke();
      this.ctx.fill()
      this.ctx.closePath()

      // 中间的圆盘
      this.ctx.beginPath()
      this.ctx.arc(this.w,this.w,this.w - this.r*1.5,0,Math.PI *2)
      this.ctx.fillStyle = grad
      this.ctx.fill()
      this.ctx.closePath();

      this.ctx.textAlign = 'center'
      this.ctx.textBaseline = 'middle'
      this.ctx.fillStyle = '#fff'
      this.ctx.font = '25px 微软雅黑'
      // this.ctx.fillText(this.percent+'%',this.w,this.w);
      this.ctx.fillText(i+'%',this.w,this.w);
      this.ctx.closePath()
    }
  }
  new Progress('canvas', 100, 10, 60);
  new Progress('canvas2', 200, 10, 90);
  let ctx = canvas3.getContext('2d');
  ctx.lineWidth = 1;
  ctx.translate(0.5,0.5);// 
  ctx.translate(-0.5,-0.5);//
  ctx.moveTo(30,30)
  ctx.lineTo(100,100)
  ctx.stroke();
</script>